home *** CD-ROM | disk | FTP | other *** search
- #
- # eight.pl : 8パズル
- #
- # 座標
- # 0 1 2
- # 3 4 5
- # 6 7 8
- #
- #
-
-
- # 外部変数定義
- $end_state = "123456780"; # 終了状態
- @state = (); # 盤面を格納(文字列で表現)
- @move_start = (); # i 手目のスタート位置
- @prev_state = (); # 一つ手前の状態
- %check_state = (); # 同一局面チェック用ハッシュ
- @adjacent = (
- [1, 3], # 0
- [0, 4, 2], # 1
- [1, 5], # 2
- [0, 4, 6], # 3
- [1, 3, 5, 7], # 4
- [2, 4, 8], # 5
- [3, 7], # 6
- [4, 6, 8], # 7
- [5, 7] # 8
- );
-
- # 盤面を表示
- sub print_state {
- my $s = shift;
- my $i;
- for( $i = 0; $i < 9; $i += 3 ){
- print substr( $s, $i, 3 ), "\n";
- }
- print "\n";
- }
-
- # 正解を逆順で表示
- sub print_history {
- my $n = shift;
- print_state( $end_state );
- while( $n != -1 ){
- my $s = $state[$n];
- &print_state( $state[$n] );
- $n = $prev_state[$n];
- }
- }
-
- # 探索
- sub search {
- my $move = 1;
- my $count = 1;
- $state[0] = shift;
- $move_start[0] = 0;
- $prev_state[0] = -1;
- $check_state{$state[0]} = 1;
- while( $count > $move_start[$move - 1] ){
- my $i = $move_start[$move - 1];
- print STDERR "$move 手の検索・・・\n\n";
- $move_start[$move] = $count;
- for( ; $i < $move_start[$move]; $i++ ){
- my $zp = index( $state[$i], '0' ); # 0 の位置を求める
-
- foreach $np ( @{ $adjacent[$zp] } ){
- my $c = substr( $state[$i], $np, 1 ); # 移動する文字を取り出す
- my $ns = $state[$i]; # 状態をコピーする
- $ns =~ s/([0$c])(.*)([0$c])/$3$2$1/; # 0 と交換する
-
- if( $end_state eq $ns ){
- # 解けた
- &print_history( $i );
- return; # 終了
- } elsif( !$check_state{$ns} ){
- # 同じ状態はない
- $state[$count] = $ns; # 状態セット
- $check_state{$ns} = 1;
- $prev_state[$count++] = $i; # 履歴セット
- }
- }
- }
- # 次の移動
- $move++;
- }
- }
-
-
- &search( "647850321" );
-
- # end of file
-
-